#include "../../include/tasktype.h"
#include "../../include/taskQueueFifo.h"
#include "../../include/scheduler.h"
#include "../../include/myPrintk.h"

//定义各种队列
FIFOLIST Waiting_Queue = {(myTCB *)0, (myTCB *)0};
FIFOLIST Ready_Queue = {(myTCB *)0, (myTCB *)0};
FIFOLIST Running_Queue = {(myTCB *)0, (myTCB *)0};
FIFOLIST *Waiting_Queue_Handler = &Waiting_Queue;
FIFOLIST *Ready_Queue_Handler = &Ready_Queue;
FIFOLIST *Running_Queue_Handler = &Running_Queue;

//程序的tid从0开始，这里标记用到了几
int tid_used = 0;

void CTX_SW();

//调试用的函数，输出队列信息
void printqueue(FIFOLIST *handler)
{
	myTCB *p = handler->start;
	int i = 0;
	while (p != 0)
	{
		myPrintk(0x6, "%d ", p->tid);
		p = p->next;
		i++;
		if (i == 8)
			break;
	}
	myPrintk(0x06, "\n");
	return;
}

//老师给的
unsigned long **prevTSK_StackPtrAddr;
unsigned long *nextTSK_StackPtr;
void context_switch(unsigned long **prevTskStkAddr, unsigned long *nextTskStk)
{
	prevTSK_StackPtrAddr = prevTskStkAddr;
	nextTSK_StackPtr = nextTskStk;
	CTX_SW();
}

//还是老师给的
void stack_init(unsigned long **stk, void (*task)(void))
{
	*(*stk)-- = (unsigned long)tskEnd; // CS
	*(*stk)-- = (unsigned long)task;   // eip
	// pushf
	*(*stk)-- = (unsigned long)0x0202; // flag registers
	// pusha
	*(*stk)-- = (unsigned long)0xAAAAAAAA; // eax
	*(*stk)-- = (unsigned long)0xCCCCCCCC; // ecx
	*(*stk)-- = (unsigned long)0xDDDDDDDD; // edx
	*(*stk)-- = (unsigned long)0xBBBBBBBB; // ebx
	*(*stk)-- = (unsigned long)0x44444444; // esp
	*(*stk)-- = (unsigned long)0x55555555; // ebp
	*(*stk)-- = (unsigned long)0x66666666; // esi
	**stk = (unsigned long)0x77777777;	   // edi
	return;
}

//创建任务，入列，建立tid
int createTsk(void (*tskBody)(void))
{
	myTCB *TCB = (myTCB *)kmalloc(sizeof(TCB));
	if (TCB == 0)
	{
		myPrintk(0x04, "kmalloc error: 01\n");
		return -1;
	}
	TCB->entry = tskBody;
	TCB->stack_end = (void *)kmalloc(STACK_SIZE);
	if (TCB->stack_end == 0)
	{
		myPrintk(0x04, "kmalloc error: 02\n");
		kfree((unsigned long)TCB);
		return -1;
	}
	TCB->stack_top = TCB->stack_end + STACK_SIZE - STACK_RESERVE;
	TCB->tid = tid_used;
	tid_used++;
	stack_init((unsigned long **)&(TCB->stack_top), tskBody);
	FIFO_enqueue(Waiting_Queue_Handler, TCB);

#if DEBUG_CREATE_TASK
	myPrintk(0x08, "created task: %d, ", TCB->tid);
	myPrintk(0x08, "waiting queue after created:");
	printqueue(Waiting_Queue_Handler);
#endif
	return TCB->tid;
}

//找找tid在哪，销毁tcb
void destroyTsk(int tid)
{
	if (tid == idleTask->tid)
		return;
	myTCB *TCB = FIFO_destroy(Waiting_Queue_Handler, tid);
	if (TCB == 0)
		TCB = FIFO_destroy(Ready_Queue_Handler, tid);
	if (TCB == 0)
		TCB = FIFO_destroy(Running_Queue_Handler, tid);
	if (TCB == 0)
		return;
	kfree((unsigned long)(TCB->stack_end));
	kfree((unsigned long)TCB);
	return;
}

//挪到就绪队列
void tskStart(int tskIndex)
{
	myTCB *TCB = FIFO_destroy(Waiting_Queue_Handler, tskIndex);
	if (TCB == 0)
		return;
	FIFO_enqueue(Ready_Queue_Handler, TCB);

#if DEBUG_QUEUE_FALGS
	myPrintk(0x08, "Starting task: tid: %d\n", TCB->tid);
	myPrintk(0x08, "|Waiting queue tid: ");
	printqueue(Waiting_Queue_Handler);
	myPrintk(0x08, "|Ready queue tid: ");
	printqueue(Ready_Queue_Handler);
#endif

	return;
}

//挪出来
void tskEnd()
{
	myTCB *TCB = FIFO_dequeue(Running_Queue_Handler);
	if (TCB == 0)
		return;

#if DEBUG_BEGIN_END
	myPrintk(0x30, "END:    tid: %d\n", TCB->tid);
#endif

	context_switch((unsigned long **)&(currentTask->stack_top), BspContext);
	return;
}

//调度
void startMultitask(void)
{
	// 内核栈
	BspContext = BspContextBase + STACK_SIZE - 1;
	currentTask = 0;
	Schedule();
	return;
}

void idleTskBody(void)
{
	myPrintk(0x3, "|            Idle Task          |\n");
	myPrintk(0x3, "|  God bless me here is no bug. |\n");
	return;
}

//初始化，只需要建立两个进程
void TaskManagerInit(void)
{

	int initTid = createTsk(initTskBody);
	int idleTid = createTsk(idleTskBody);
	idleTask = Waiting_Queue_Handler->end;
	tskStart(initTid);

	startMultitask();
	return;
}

//调度
void FIFO_schedule(FIFOLIST *tskhandler)
{
#if DEBUG_BEGIN_END
	static int IfPrintDebugMessage = 1;
	if (IfPrintDebugMessage)
		myPrintk(0x40, "Start schedule\n");
	IfPrintDebugMessage = (int)(currentTask != idleTask); //进入idletask后这玩应只显示一次，免得一直刷屏
#endif

	while (1)
	{
		myTCB *nextTask = FIFO_gettop(Ready_Queue_Handler);

		if (nextTask == idleTask && currentTask == idleTask)
			continue;

		if (currentTask != 0)
			destroyTsk(currentTask->tid);

#if DEBUG_QUEUE_FALGS
		int curtid = (currentTask == 0) ? -1 : currentTask->tid;
		int nexttid = (nextTask == 0) ? -1 : nextTask->tid;
		myPrintk(0x08, "\nCurrent task: %d, next task: %d\n", curtid, nexttid);
#endif

		nextTask->task_state = RUNNING;
		currentTask = nextTask;

#if DEBUG_QUEUE_FALGS
		myPrintk(0x08, "Before changing the queue:\n");
		myPrintk(0X08, "|Ready   queue: ");
		printqueue(Ready_Queue_Handler);
		myPrintk(0x08, "|Running queue: ");
		printqueue(Running_Queue_Handler);
		myPrintk(0x08, "|Waiting queue: ");
		printqueue(Waiting_Queue_Handler);
#endif

		FIFO_dequeue(Ready_Queue_Handler);
		FIFO_enqueue(Running_Queue_Handler, currentTask);
		if (currentTask == idleTask)
			FIFO_destroy(Waiting_Queue_Handler, idleTask->tid);

#if DEBUG_QUEUE_FALGS
		myPrintk(0x08, "After changed the queue:\n");
		myPrintk(0X08, "|Ready   queue: ");
		printqueue(Ready_Queue_Handler);
		myPrintk(0x08, "|Running queue: ");
		printqueue(Running_Queue_Handler);
		myPrintk(0x08, "|Waiting queue: ");
		printqueue(Waiting_Queue_Handler);
		myPrintk(0x08, "\n");
#endif
		unsigned long **p = &BspContext;

#if DEBUG_BEGIN_END
		myPrintk(0x40, "START:  tid: %d\n", currentTask->tid);
#endif

		context_switch(p, currentTask->stack_top);
	}
	return;
}
